﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;

namespace Excel2CS
{
    internal class ScriptGenerator
    {
        //脚本生成器

        string className;
        List<string> propertyNames;
        List<string> propertyTypes;
        List<string> propertyComments;
        List<List<KeyValuePair<string, string>>> propertyValueDic;

        public ScriptGenerator(string tableName, string[] names, string[] types, string[] comments, List<List<KeyValuePair<string, string>>> valueDic)
        {
            className = tableName;
            propertyNames = new(names);
            propertyTypes = new(types);
            propertyComments = new(comments);
            propertyValueDic = valueDic;
        }

        //创建代码
        public string CreateCode()
        {
            //生成类
            StringBuilder classSource = new();
            classSource.Append("/* Auto created by Excel2CS, Don't Edit it. */\r\n");
            classSource.Append("\r\n");
            classSource.Append("using System;\r\n");
            classSource.Append("using System.Reflection;\r\n");
            classSource.Append("using System.Collections.Generic;\r\n");
            classSource.Append("\r\n");
            classSource.Append("namespace Config\r\n");
            classSource.Append("{\r\n");
            classSource.Append("public class " + className + "\r\n");
            classSource.Append("{\r\n");
            //声明变量
            for (int i = 0; i < propertyNames.Count; i++)
            {
                classSource.Append(PropertyString(propertyNames[i], propertyTypes[i], propertyComments[i]));
            }

            classSource.Append("\r\n");
            classSource.Append(string.Format("\tpublic static Dictionary<int, {0}> data = new()\r\n", className));
            classSource.Append("\t{\r\n");
            {
                foreach (var lineData in propertyValueDic)
                {
                    classSource.Append("{\r\n");
                    {
                        var idPair = lineData[0]; //lineData.Find((kv) => { return kv.Key == "id"; }); //primary key
                        classSource.Append(string.Format("\t{0}, new {1}\r\n", idPair.Value, className)); //1, new TestTable
                        {
                            classSource.Append("\t{\r\n");
                            foreach (var kv in lineData)
                            {
                                if (string.IsNullOrEmpty(kv.Value))
                                    continue;
                                int index = propertyNames.IndexOf(kv.Key);
                                string type = propertyTypes[index];
                                string value = Assignment(type, kv.Value);
                                classSource.Append(string.Format("\t\t{0} = {1},\r\n", kv.Key, value));
                            }
                            classSource.Append("\t}\r\n");
                        }
                    }
                    classSource.Append("},\r\n");
                }
            }
            classSource.Append("\t};\r\n");


            //
            classSource.Append("}\r\n");
            classSource.Append("}\r\n");

            return classSource.ToString();
        }

        static readonly string[] EnumPropertyTypes = [
            "int", "float", "string", "bool",
            "int[]", "float[]", "string[]", "bool[]",
            "I18N.key", "I18N.value",
            "KeyValuePair<int, int>[]", "KeyValuePair<int, int>[][]", "int[][]"
            //"SortedDictionary<int, int>", "SortedDictionary<int, int>[]"
            ];

        static string PropertyString(string name, string type, string comment)
        {
            if (string.IsNullOrEmpty(name))
                return "";
            if (!EnumPropertyTypes.Contains(type))
            {
                Console.WriteLine("===Warning:未定义的类型：{0} 当成字符串处理！", type);
                //string str = EnumPropertyTypes.First(s => s == type);
                //if (string.IsNullOrEmpty(str))
                type = "string"; //default
            }
            else
            {
                //国际化，先简单处理
                if (type == "I18N.key")
                    type = "int";
                else if (type == "I18N.value")
                    type = "string";
            }
            string propertyStr =
                $"\t/// <summary>\r\n" +
                $"\t/// {comment}\r\n" +
                $"\t/// </summary>\r\n" +
                $"\tpublic {type} {name};\r\n";
            return propertyStr;
        }
        #region
        private string Assignment(string type, string value)
        {
            Func<string, string> CheckPropertyAct;

            StringBuilder source = new();

            //match:EnumPropertyTypes
            Func<string, string>[] CheckPropertyActs = [
                CheckProperty_Int, CheckProperty_Float, CheckProperty_String, CheckProperty_Bool,
                CheckProperty_ArrayInt, CheckProperty_ArrayFloat, CheckProperty_ArrayString, CheckProperty_ArrayBool,
                CheckProperty_Int, CheckProperty_String, //for "I18N.key", "I18N.value",
                CheckProperty_KvArray, CheckProperty_KvArrayArr, CheckProperty_IntArrayArr
                //CheckProperty_Dic, CheckProperty_DicArray
                ];
            List<string> arr = new(EnumPropertyTypes);
            int index = arr.IndexOf(type);
            if (index >= 0)
                CheckPropertyAct = CheckPropertyActs[index];
            else
                CheckPropertyAct = CheckProperty_String;

            source.Append(CheckPropertyAct(value));

            return source.ToString();
        }

        private string CheckProperty_Int(string value)
        {
            return Convert.ToInt32(value).ToString();
        }
        private string CheckProperty_Float(string value)
        {
            return Convert.ToSingle(value) + "f";
        }
        private string CheckProperty_String(string value)
        {
            //return string.Format(@"""{0}""", value);
            //return "\"" + value + "\"";
            // 使用 JsonSerializer 进行安全转义，保证任意字符串内容的正确性。
            return JsonSerializer.Serialize(value); // "\u8D85\u5E02\u4E8B\u4EF6"
        }
        private string CheckProperty_Bool(string value)
        {
            var a = Convert.ToBoolean(value); //False
            var b = a.ToString().ToLower();
            //Console.WriteLine("{0}{1}{2}", value, a, b);
            return b;
        }

        private string CheckProperty_ArrayInt(string value)
        {
            return CheckProperty_Array("int[]", value, CheckProperty_Int);
        }
        private string CheckProperty_ArrayFloat(string value)
        {
            return CheckProperty_Array("float[]", value, CheckProperty_Float);
        }
        private string CheckProperty_ArrayString(string value)
        {
            return CheckProperty_Array("string[]", value, CheckProperty_String);
        }
        private string CheckProperty_ArrayBool(string value)
        {
            return CheckProperty_Array("bool[]", value, CheckProperty_Bool);
        }
        static string CheckProperty_Array(string type, string value, Func<string, string> CheckProperty)
        {
            if (value == null)
                return "";
            var arr = value.Split('|');
            if (arr.Length == 0)
                return "";
            string str = "new " + type + "{"; // string.Format("new {0} {", type);
            StringBuilder stringBuilder = new(str);
            for (int i = 0; i < arr.Length; i++)
            {
                var s = CheckProperty(arr[i]);
                stringBuilder.Append(s + ",");
            }
            stringBuilder.Remove(stringBuilder.Length - 1, 1);
            stringBuilder.Append('}');
            return stringBuilder.ToString();
        }

        private string CheckProperty_KvArray(string value)
        {
            string type = "KeyValuePair<int, int>[]";
            if (value == null)
                return "";
            var arr = value.Split('|');
            if (arr.Length == 0)
                return "";
            string str = "new " + type + "{"; // string.Format("new {0} {", type);
            StringBuilder stringBuilder = new(str);
            for (int i = 0; i < arr.Length; i++)
            {
                string[] s;
                if (arr[i].Contains(':'))
                    s = arr[i].Split(':');
                else
                    s = arr[i].Split('-');
                var k = CheckProperty_Int(s[0]);
                var v = CheckProperty_Int(s[1]);
                //stringBuilder.Append($"{{{k},{v}}},");// s + ",");
                stringBuilder.Append($"new( {k}, {v} ),");
            }
            stringBuilder.Remove(stringBuilder.Length - 1, 1);
            stringBuilder.Append('}');
            return stringBuilder.ToString();
        }

        private string CheckProperty_KvArrayArr(string value)
        {
            string type = "KeyValuePair<int, int>[][]";
            if (value == null)
                return "";
            var arr = value.Split('|');
            if (arr.Length == 0)
                return "";
            string str = "new " + type + "{\r\n"; // string.Format("new {0} {", type);
            StringBuilder stringBuilder = new(str);
            for (int j = 0; j < arr.Length; j++)
            {
                var arr2 = arr[j].Split('/');
                if (arr.Length == 0)
                    return "";
                string str2 = "new KeyValuePair<int, int>[] {"; // string.Format("new {0} {", type);
                stringBuilder.Append(str2);

                for (int i = 0; i < arr2.Length; i++)
                {
                    string[] s;
                    if (arr2[i].Contains(':'))
                        s = arr2[i].Split(':');
                    else
                        s = arr2[i].Split('-');

                    string v;
                    var k = CheckProperty_Int(s[0]);
                    //if (k == "0")
                        //continue;
                    if (s.Length == 1) // 只有一个数字时，当成key，value给0
                        v = "0";
                    else
                        v = CheckProperty_Int(s[1]);

                    //stringBuilder.Append($"{{{k},{v}}},");// s + ",");
                    stringBuilder.Append($"new( {k}, {v} ),");
                }
                stringBuilder.Append("},\r\n");
            }
            //stringBuilder.Remove(stringBuilder.Length - 1, 1);
            stringBuilder.Append('}');
            return stringBuilder.ToString();
        }

        //int[][] aa = new[]{ new int[] { 1, 2, }, new int[] { 3 } };
        private string CheckProperty_IntArrayArr(string value)
        {
            if (value == null)
                return "";
            var arr = value.Split('|');
            if (arr.Length == 0)
                return "";
            string str = "new[]{";
            StringBuilder stringBuilder = new(str);
            for (int j = 0; j < arr.Length; j++)
            {
                var arr2 = arr[j].Split('/');
                if (arr.Length == 0)
                    return "";
                string str2 = "new int[] {"; // string.Format("new {0} {", type);
                stringBuilder.Append(str2);

                for (int i = 0; i < arr2.Length; i++)
                {
                    var v = CheckProperty_Int(arr2[i]);
                    stringBuilder.Append($"{v},");
                }
                stringBuilder.Append("},");
            }
            stringBuilder.Remove(stringBuilder.Length - 1, 1);
            stringBuilder.Append('}');
            return stringBuilder.ToString();
        }
        /*
        KeyValuePair<int, int>[] aa = new KeyValuePair<int, int>[] { new(1, 1), new(2, 2) };
        KeyValuePair<int, int>[][] bb = new KeyValuePair<int, int>[][] 
        { 
            new KeyValuePair<int, int>[] { new(1, 1), new(2, 2) } ,
            new KeyValuePair<int, int>[] { new(1, 1), new(2, 2) } ,
        };
        
        KeyValuePair<int, int> aaa = new(1, 1);
        Dictionary<int, int> dic00 = new() { { 1, 1 }, { 2, 2 } };
        SortedDictionary<int, int> dic11 = new() { { 1, 1 }, { 2, 2 } };
        
        SortedDictionary<int, int>[] dicArr // = [new() { { 1, 1 }, { 2, 2 } }, new() { { 1, 1 }, { 2, 2 } }];//c#9不支持
            = new SortedDictionary<int, int>[] { new() { { 1, 1 }, { 2, 2 } }, new() { { 1, 1 }, { 2, 2 } } };
        */
        /* 字典不能通过下标访问，实际应用中不方便
        private string CheckProperty_Dic(string value)
        {
            //string type = "SortedDictionary<int, int>";
            if (value == null)
                return "";
            var arr = value.Split('/');
            if (arr.Length == 0)
                return "";
            string str = "new()" + "{"; // string.Format("new {0} {", type);
            StringBuilder stringBuilder = new(str);
            for (int i = 0; i < arr.Length; i++)
            {
                string[] s;
                if (arr[i].Contains(':'))
                    s = arr[i].Split(':');
                else
                    s = arr[i].Split('-');

                string v;
                var k = CheckProperty_Int(s[0]);
                if (k == "0")
                    continue;
                if (s.Length == 1) // 只有一个数字时，当成key，value给0
                    v = "0";
                else 
                    v = CheckProperty_Int(s[1]);
                
                stringBuilder.Append($"{{ {k}, {v} }},");
            }
            //stringBuilder.Remove(stringBuilder.Length - 1, 1);
            stringBuilder.Append('}');
            return stringBuilder.ToString();
        }

        private string CheckProperty_DicArray(string value)
        {
            if (value == null)
                return "";
            var arr = value.Split('|');
            if (arr.Length == 0)
                return "";
            string str = "new SortedDictionary<int, int>[] {";
            StringBuilder stringBuilder = new(str);
            for (int i = 0; i < arr.Length; i++)
            {
                var s = CheckProperty_Dic(arr[i]);
                stringBuilder.Append(s + ",");
            }
            stringBuilder.Remove(stringBuilder.Length - 1, 1);
            stringBuilder.Append('}');
            return stringBuilder.ToString();
        }
        */
        #endregion
    }
}
